﻿//
//  THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
//  KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
//  IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
//  PURPOSE.
//
//  License: GNU General Public License version 3 (GPLv3)
//
//  Email: pavel_torgashov@mail.ru.
//
//  Copyright (C) Pavel Torgashov, 2011. 

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
using Emgu.CV;
using Emgu.CV.Structure;
//using ContourAnalysisNS;
using uitocr.imaging.ContourAnalysisNS;
using uitocr.imaging.Settings;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;


namespace ContourAnalysisDemo
{
    public partial class MainForm : Form
    {
        int recognitionMethod = 1;
        bool processed = false;
        private Capture _capture;
        Setting setting_ = new Setting(false);        
        
        Dictionary<string, Image> AugmentedRealityImages = new Dictionary<string, Image>();
        Image<Bgr, Byte> frame;
        ImageProcessor processor;

       
        bool captureFromCam = true;
        int frameCount = 0;
        int oldFrameCount = 0;
        bool showAngle;
        int camWidth = 640;
        int camHeight = 480;
        string templateFile;
        private static readonly string[] letters = 
        {
            "A", "a", "B", "b", "c", "C", "d","Đ", "D", 
            "đ", "e", "E", "F", "f", "G", "g","h", "H",
            "I", "J", "K", "k", "L", "l" ,"m","M", "N",
            "n", "o", "P", "Q", "q", "R" ,"r","S", "T",
            "t", "u", "Ư", "U", "ư", "V" ,"W","X", "Y",
            "y", "z", 
            // tahoma
            "A" ,"a" ,"B" ,"b", "c", "d", "D", "Đ", "đ", "e",
            "E" ,"F" ,"f" ,"G", "g", "h", "H", "I", "J", "K",
            "k" ,"L" ,"m" ,"M" ,"N", "n", "o", "p", "P", "Q",
            "q" ,"R" ,"r" ,"S" ,"T", "t", "u", "ư", "U", "Ư",
            "v" ,"W" ,"X" ,"Y" ,"y", "z", "l", "p",
            //times new roman sign
            "`","/","~","?","^","_","A", "B", "C", "D", "E",
            "F", "G", "H", "I",
            "J", "K", "L", "M", "N", "O", "P", "Q", "R",
            "S", "T", "U", "V", "W", "X", "Y", "Z"


        };
        
        
        

        


        public MainForm()
        {
            InitializeComponent();
            //create image preocessor
            
          //processor = new ImageProcessor(recognitionMethod);
          
        //    processor.numofObject = 1;
            //comboBox1.SelectedIndex = recognitionMethod - 1;
            
            //load default templates
            templateFile = AppDomain.CurrentDomain.BaseDirectory + "\\Tahoma.bin";
            setting_.nonadaptivethreshold = 160;
            setting_.Do_resize = true;
            setting_.size = new uitocr.imaging.scaleSize(40, 40);
            //start capture from cam
            StartCapture();
            processor = new ImageProcessor(1);
            comboBox1.SelectedIndex = 0;
            
            //apply settings
            ApplySettings();
            //
            //if(recognitionMethod == 1)
            //Application.Idle += new EventHandler(Application_Idle);
            
        }

        private void LoadTemplates(string fileName)
        {
            try
            {
                using(FileStream fs = new FileStream(fileName, FileMode.Open))
                    processor.templates = (Templates)new BinaryFormatter().Deserialize(fs);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        private void SaveTemplates(string fileName)
        {
            try
            {
                using (FileStream fs = new FileStream(fileName, FileMode.Create))
                    new BinaryFormatter().Serialize(fs, processor.templates);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        private void StartCapture()
        {
            try
            {
                _capture = new Capture();
                ApplyCamSettings();
            }
            catch (NullReferenceException ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        private void ApplyCamSettings()
        {
            try
            {
                _capture.SetCaptureProperty(Emgu.CV.CvEnum.CAP_PROP.CV_CAP_PROP_FRAME_WIDTH, camWidth);
                _capture.SetCaptureProperty(Emgu.CV.CvEnum.CAP_PROP.CV_CAP_PROP_FRAME_HEIGHT, camHeight);
                cbCamResolution.Text = camWidth + "x" + camHeight;
            }
            catch (NullReferenceException ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        void Application_Idle(object sender, EventArgs e)
        {
         
                ProcessFrameWithCAi();
            
        }
        private void processFrameWithRemain()
        {
            try
            {
                // processex = new ImageProcessor(2);
                processor.blob_collected = new List<uitocr.imaging.Blob>();
                    frameCount++;

                     
                    //
                
                    
                    processor.process(frame ,  setting_);
                    
                    
                    
                    Font font = new Font(Font.FontFamily, 24);//16
                    Brush bgBrush = new SolidBrush(Color.FromArgb(255, 0, 0, 0));
                    Brush foreBrush = new SolidBrush(Color.FromArgb(255, 255, 255, 255));
                    Pen borderPen = new Pen(Color.FromArgb(150, 0, 255, 0));
                    Bitmap bm = (Bitmap)frame.ToBitmap();
                    Graphics g = Graphics.FromImage(bm);
                    foreach (uitocr.imaging.Blob blob_ in processor.blob_collected)
                    {
                        
                        Rectangle objectRect = blob_.Rectangle;
                        int obWidth = objectRect.Width;
                        int obHeight = objectRect.Height;
                        g.DrawRectangle(borderPen, blob_.Rectangle);
                        g.DrawString(letters[blob_.Label], font, foreBrush, new PointF(objectRect.X - font.Height / 3, objectRect.Y - font.Height));
                        g.DrawString(letters[blob_.Label], font, bgBrush, new PointF(objectRect.X + 1 - font.Height / 3, objectRect.Y + 1 - font.Height));

                    }

                    ibMain.Image = new Image<Bgr, byte>(bm); ;
                    showSkeletonedToolStripMenuItem.Visible = true;
                    rectanglesBoundToolStripMenuItem.Visible = true;
                    mnShowBinarized.Visible = true;
                    if (mnShowBinarized.Checked)
                        ibMain.Image =  processor.binarizedFrame;
                    if (showSkeletonedToolStripMenuItem.Checked)
                        ibMain.Image = processor.SkeletonedFrame;
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
            
        }
        private void ProcessFrameWithCAi()
        {
            try
            {

                
                processor.ProcessImage(frame);
                
                mnShowBinarized.Visible = true;
                        
                //
                if(mnShowBinarized.Checked)
                    ibMain.Image = processor.binarizedFrame;
                else
                    ibMain.Image = frame;
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }
        
        private void tmUpdateState_Tick(object sender, EventArgs e)
        {

        }
        
        private void ibMain_Paint(object sender, PaintEventArgs e)
        {
            if (frame == null) return;

            Font font = new Font(Font.FontFamily, 24);//16

            e.Graphics.DrawString(lbFPS.Text, new Font(Font.FontFamily, 16), Brushes.Yellow, new PointF(1, 1));

            Brush bgBrush = new SolidBrush(Color.FromArgb(255, 0, 0, 0));
            Brush foreBrush = new SolidBrush(Color.FromArgb(255, 255, 255, 255));
            Pen borderPen = new Pen(Color.FromArgb(150, 0, 255, 0));
            //
            /*
               
             * 

            */
            if (recognitionMethod == 1)
            {
                try
                {


                    if (mnShowContours.Checked)
                        foreach (var contour in processor.contours)
                            if (contour.Total > 1)
                                e.Graphics.DrawLines(Pens.Red, contour.ToArray());
                    //

                    lock (processor.foundTemplates)
                        foreach (FoundTemplateDesc found in processor.foundTemplates)
                        {

                            /*
                            if (found.template.name.EndsWith(".png") || found.template.name.EndsWith(".jpg"))
                            {
                                DrawAugmentedReality(found, e.Graphics);
                                continue;
                            }
                            */
                            Rectangle foundRect = found.sample.contour.SourceBoundingRect;
                            Point p1 = new Point((foundRect.Left + foundRect.Right) / 2, foundRect.Top);
                            string text = found.template.name;
                            if (showAngle)
                                text += string.Format("\r\nangle={0:000}°\r\nscale={1:0.0}", 180 * found.angle / Math.PI, found.scale);
                            e.Graphics.DrawRectangle(borderPen, foundRect);
                            e.Graphics.DrawString(text, font, bgBrush, new PointF(p1.X + 1 - font.Height / 3, p1.Y + 1 - font.Height));
                            e.Graphics.DrawString(text, font, foreBrush, new PointF(p1.X - font.Height / 3, p1.Y - font.Height));
                        }
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
                }

            }
        }

        private void DrawAugmentedReality(FoundTemplateDesc found, Graphics gr)
        {
            string fileName = Path.GetDirectoryName(templateFile) + "\\" + found.template.name;
            if (!AugmentedRealityImages.ContainsKey(fileName))
            {
                if (!File.Exists(fileName)) return;
                AugmentedRealityImages[fileName] = Image.FromFile(fileName);
            }
            Image img = AugmentedRealityImages[fileName];
            Point p = found.sample.contour.SourceBoundingRect.Center();
            var state = gr.Save();
            gr.TranslateTransform(p.X, p.Y);
            gr.RotateTransform((float)(180f * found.angle / Math.PI));
            gr.ScaleTransform((float)(found.scale), (float)(found.scale));
            gr.DrawImage(img, new Point(-img.Width/2, -img.Height/2));
            gr.Restore(state);
        }

        private void cbAutoContrast_CheckedChanged(object sender, EventArgs e)
        {
            ApplySettings();
            
        }

        private void ApplySettings()
        {
            try
            {
                
                
                showAngle = mnShowAngle.Checked;
                captureFromCam = cbCaptureFromCam.Checked;
                btLoadImage.Enabled = !captureFromCam;
                cbCamResolution.Enabled = captureFromCam;
                
                supportVectorMachineToolStripMenuItem.Checked = comboBox1.SelectedIndex == 1;
                neuralNetworksToolStripMenuItem.Checked = comboBox1.SelectedIndex == 2;
                contourAnalisysToolStripMenuItem.Checked = comboBox1.SelectedIndex == 0;
                analysisModecheckbox.Enabled = !(comboBox1.SelectedIndex == 0);
                ContourFunctionSettingGroupBox.Enabled = (comboBox1.SelectedIndex == 0);
                groupBox2.Enabled = (comboBox1.SelectedIndex == 0);
                groupBox10.Enabled = (comboBox1.SelectedIndex == 0);
                groupBox6.Enabled = !(comboBox1.SelectedIndex == 0);
                cameraToolStripMenuItem.Visible = comboBox1.SelectedIndex == 0;

                recognitionMethod = comboBox1.SelectedIndex == 0 ? 1 : 2;



                canvasToolStripMenuItem.Visible = comboBox1.SelectedIndex != 0;
                
                
                cblostcheck.Enabled = cbdilate.Checked;
                
                nuddilate.Enabled = cbdilate.Checked||cbdilate.Enabled;
                nudresize.Enabled = cbresize.Checked;
                
                
                cbresize.Enabled = comboBox1.SelectedIndex != 0;
                cblostcheck.Enabled = cbdilate.Checked;
                nuddilate.Enabled = cbdilate.Checked;
                cbdilate.Enabled = comboBox1.SelectedIndex != 0;

                nudBinaryThreshold.Enabled = ThreshShold.Checked;
                nudAdaptiveThBlockSize.Enabled = cbBinAdaptiveThreshold.Checked;
                cbAdaptiveNoiseFilter.Enabled = cbBinAdaptiveThreshold.Checked;
                setting_.nonadaptivethreshold = (int)nudBinaryThreshold.Value;
                nudMinDefinition.Enabled = cbNoiseFilter.Checked;
                processor.finder.maxRotateAngle = cbAllowAngleMore45.Checked ? Math.PI : Math.PI / 4;
                processor.minContourArea = (int)nudMinContourArea.Value;
                processor.minContourLength = (int)nudMinContourLength.Value;
                processor.finder.maxACFDescriptorDeviation = (int)nudMaxACFdesc.Value;
                processor.finder.minACF = (double)nudMinACF.Value;
                processor.finder.minICF = (double)nudMinICF.Value;
                processor.blur = cbBlur.Checked;
                processor.BinarizeAdaptiveMethod = cbBinAdaptiveThreshold.Checked;
                processor.noiseFilter = cbNoiseFilter.Checked;
                processor.equalizeHist = cbAutoContrast.Checked;
                processor.cannyThreshold = (int)nudMinDefinition.Value;

                processor.adaptiveThresholdBlockSize = (int)nudAdaptiveThBlockSize.Value;
                processor.adaptiveThresholdParameter = cbAdaptiveNoiseFilter.Checked ? 1.5 : 0.5;
                
                processor.BinarizeAdaptiveMethod = cbBinAdaptiveThreshold.Checked;
                setting_.LostChecking = cblostcheck.Checked;
                setting_.dialte = cbdilate.Checked;
                setting_.Do_resize = cbresize.Checked;
                setting_.size = new uitocr.imaging.scaleSize((int)nudresize.Value, (int)nudresize.Value);
                //cam resolution
                string[] parts = cbCamResolution.Text.ToLower().Split('x');
                if (parts.Length == 2)
                {
                    int camWidth = int.Parse(parts[0]);
                    int camHeight = int.Parse(parts[1]);
                    if (this.camHeight != camHeight || this.camWidth != camWidth)
                    {
                        this.camWidth = camWidth;
                        this.camHeight = camHeight;
                        ApplyCamSettings();
                    }
                }
            }
            catch(Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        private void btLoadImage_Click(object sender, EventArgs e)
        {
            LoadImage();
        }
        void LoadImage()
        {
            OpenFileDialog ofd = new OpenFileDialog();
            ofd.Filter = "Image|*.bmp;*.png;*.jpg;*.jpeg";
            if (ofd.ShowDialog(this) == System.Windows.Forms.DialogResult.OK)
                try
                {
                    frame = new Image<Bgr, byte>((Bitmap)Bitmap.FromFile(ofd.FileName));
                    ibMain.Image = frame;
                    processed = false;

                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message);
                }
        }

        private void btCreateTemplate_Click(object sender, EventArgs e)
        {
            if(frame!=null)
                new ShowContoursForm(processor.templates, processor.samples, frame).ShowDialog();
        }

        private void btNewTemplates_Click(object sender, EventArgs e)
        {
            if (MessageBox.Show("Do you want to create new template database?", "Create new template database", MessageBoxButtons.OKCancel) == System.Windows.Forms.DialogResult.OK)
                processor.templates.Clear();
        }

        private void btOpenTemplates_Click(object sender, EventArgs e)
        {
            OpenFileDialog ofd = new OpenFileDialog();
            ofd.Filter = "Templates(*.bin)|*.bin";
            if (ofd.ShowDialog(this) == System.Windows.Forms.DialogResult.OK)
            {
                templateFile = ofd.FileName;
                LoadTemplates(templateFile);
            }
        }

        private void btSaveTemplates_Click(object sender, EventArgs e)
        {
            SaveFileDialog sfd = new SaveFileDialog();
            sfd.Filter = "Templates(*.bin)|*.bin";
            if (sfd.ShowDialog(this) == System.Windows.Forms.DialogResult.OK){
                templateFile = sfd.FileName;
                SaveTemplates(templateFile);
            }
        }

        private void btTemplateEditor_Click(object sender, EventArgs e)
        {
            new TemplateEditor(processor.templates).Show();
        }

        private void btAutoGenerate_Click(object sender, EventArgs e)
        {
            new AutoGenerateForm(processor).ShowDialog();
        }

        private void neuralNetworksToolStripMenuItem_Click(object sender, EventArgs e)
        {
            
            if (neuralNetworksToolStripMenuItem.Checked)
            {
                comboBox1.SelectedIndex = 2;
            
            
            }
                
                groupBox2.Enabled = !neuralNetworksToolStripMenuItem.Checked;

                fromImageToolStripMenuItem.Visible = neuralNetworksToolStripMenuItem.Checked;
                cameraToolStripMenuItem.Visible = !neuralNetworksToolStripMenuItem.Checked;
                canvasToolStripMenuItem.Visible = neuralNetworksToolStripMenuItem.Checked;
            
            
            
        }
        
        private void supportVectorMachineToolStripMenuItem_Click(object sender, EventArgs e)
        {
            
            if (supportVectorMachineToolStripMenuItem.Checked)
            {
                comboBox1.SelectedIndex = 1;
                this.recognitionMethod = 2;
            
            }
            
            fromImageToolStripMenuItem.Visible = true;

            groupBox2.Enabled = !supportVectorMachineToolStripMenuItem.Checked;
            cameraToolStripMenuItem.Visible = !supportVectorMachineToolStripMenuItem.Checked;
            canvasToolStripMenuItem.Visible = supportVectorMachineToolStripMenuItem.Checked;
            
        }

        private void nothing(object sender , EventArgs e)
        {

        }

        private void contourAnalisysToolStripMenuItem_Click(object sender, EventArgs e)
        {
            
            if (contourAnalisysToolStripMenuItem.Checked)
            {
                comboBox1.SelectedIndex = 0;
                this.recognitionMethod = 1;
            
            }
            fromImageToolStripMenuItem.Visible = contourAnalisysToolStripMenuItem.Checked;
            cameraToolStripMenuItem.Visible = contourAnalisysToolStripMenuItem.Checked ;
            canvasToolStripMenuItem.Visible = !contourAnalisysToolStripMenuItem.Checked;
            groupBox2.Enabled = contourAnalisysToolStripMenuItem.Checked;
            
            
        }

        private void mnShowBinarized_Click(object sender, EventArgs e)
        {
            ibMain.Image = processor.binarizedFrame;
            
        }

        private void panelToolStripMenuItem_Click(object sender, EventArgs e)
        {

            if (panelToolStripMenuItem.Checked)
                pnSettings.Visible = true;
            else
                pnSettings.Visible = false;
        }

        private void recognitionParameterToolStripMenuItem_Click(object sender, EventArgs e)
        {
            pnSettings.Show();
        }

        private void numericUpDown4_ValueChanged(object sender, EventArgs e)
        {

        }

        private void checkBox3_CheckedChanged(object sender, EventArgs e)
        {
            ApplySettings();

        }

        private void ThreshShold_CheckedChanged(object sender, EventArgs e)
        {
            
            cbBinAdaptiveThreshold.Checked = !ThreshShold.Checked;
            ApplySettings();
        }

        private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (comboBox1.SelectedIndex == 0)
            {
                cbBinAdaptiveThreshold.Checked = true;

                processor = new ImageProcessor(2);
            }
            else
            {
                ThreshShold.Checked = true;
                processor = new ImageProcessor(1);
                LoadTemplates(templateFile);
            }
            ApplySettings();
            
        }

        private void button1_Click(object sender, EventArgs e)
        {

            processe(comboBox1.SelectedIndex == 0  ,e);
            
        }

        private void processe(bool p , EventArgs e)
        {
            if (p)
            {
                processor = new ImageProcessor(1);
                LoadTemplates(templateFile);
                ProcessFrameWithCAi();
                Application.Idle += new EventHandler(Application_Idle);

            }
            else
            {
                
                processFrameWithRemain();
                Application.Idle -= new EventHandler(Application_Idle);
            }
        }
        
        private void openImageToolStripMenuItem_Click(object sender, EventArgs e)
        {
            LoadImage();
        }

        

        private void checkBox6_CheckedChanged(object sender, EventArgs e)
        {

            ApplySettings();
        }

        private void nudBinaryThreshold_ValueChanged(object sender, EventArgs e)
        {
            ApplySettings();
            //setting_.nonadaptivethreshold = (int)nudBinaryThreshold.Value;
        }

        

        private void checkBox2_CheckedChanged(object sender, EventArgs e)
        {
            ApplySettings();
        }

        private void numericUpDown2_ValueChanged(object sender, EventArgs e)
        {

        }

        private void numericUpDown1_ValueChanged(object sender, EventArgs e)
        {

        }

        private void checkBox1_CheckedChanged(object sender, EventArgs e)
        {
            ApplySettings();
        }

        private void cbAdaptiveNoiseFilter_CheckedChanged(object sender, EventArgs e)
        {
            ApplySettings();
        }

        private void cbBlur_CheckedChanged(object sender, EventArgs e)
        {
            ApplySettings();
        }

        private void nudAdaptiveThBlockSize_ValueChanged(object sender, EventArgs e)
        {
            ApplySettings();
        }

        private void cbBinAdaptiveThreshold_CheckedChanged(object sender, EventArgs e)
        {
            
            ThreshShold.Checked =! cbBinAdaptiveThreshold.Checked ;
            ApplySettings();
        }

        private void cbAutoContrast_CheckedChanged_1(object sender, EventArgs e)
        {
            ApplySettings();
        }

        private void fromImageToolStripMenuItem_Click(object sender, EventArgs e)
        {
            LoadImage();
        }

        private void moreToolStripMenuItem_Click(object sender, EventArgs e)
        {
            NeuronDotNet.Samples.CharacterRecognition.newstyle newst = new NeuronDotNet.Samples.CharacterRecognition.newstyle();
            newst.ShowDialog();
        }

        

        
    }
}
